package org.xindian.lbstest;

import java.util.Collections;
import java.util.HashSet;
import java.util.Vector;

import org.xindian.lbstest.lbs.CDMACell;
import org.xindian.lbstest.lbs.GSMCell;

import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.telephony.CellLocation;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.telephony.cdma.CdmaCellLocation;
import android.telephony.gsm.GsmCellLocation;

public class LBSManager {
	private LBSTestActivity context=null;
	private static LBSManager lbsManager=null;
	
	private LocationManager locationManager;
	private TelephonyManager telephonyManager;
	
	private int phoneType = -1;
	private boolean networkLocationOn=false;
	private boolean gpsLocationOn=false;
	private PhoneLocation lastKnownGpsLocation = new PhoneLocation();
	private PhoneLocation lastKnownNetworkLocation = new PhoneLocation();
	
	private Vector<GSMCell> gsmCells = new Vector<GSMCell>();
	private Vector<CDMACell> cdmaCells = new Vector<CDMACell>();

	private PhoneStateListener phoneStateListener = new PhoneStateListener() {
		public void onCellLocationChanged(CellLocation location) {
			if ((location instanceof GsmCellLocation)) {
				phoneType = 1;
				GsmCellLocation loc = (GsmCellLocation) location;
				GSMCell gsmCell = new GSMCell(loc.getCid(),loc.getLac(),System.currentTimeMillis());
				if ((gsmCell.lac != -1) && (gsmCell.cid != -1)) {
					gsmCells.add(0, gsmCell);
					Vector<GSMCell> tempCells = new Vector<GSMCell>(new HashSet<GSMCell>(gsmCells));
					Collections.sort(tempCells);
					if (tempCells.size() > 10) {
						tempCells.subList(10, tempCells.size()).clear();
					}
					gsmCells.clear();
					gsmCells.addAll(tempCells);
				}
			} else {
				try {
					// check if CdmaCellLocation is exists.
					Class.forName("android.telephony.cdma.CdmaCellLocation");
					
					phoneType = 2;
					CdmaCellLocation cdma = (CdmaCellLocation)location;

					CDMACell cdmaCell = new CDMACell();
					cdmaCell.stationId = (cdma.getBaseStationId() < 0 ? cdmaCell.stationId
							: cdma.getBaseStationId());
					cdmaCell.networkId = (cdma.getNetworkId() < 0 ? cdmaCell.networkId
							: cdma.getNetworkId());
					cdmaCell.systemId = (cdma.getSystemId() < 0 ? cdmaCell.systemId
							: cdma.getSystemId());
					cdmaCell.time = System.currentTimeMillis();
					int lat = cdma.getBaseStationLatitude();
					int lon = cdma.getBaseStationLongitude();
					if ((lat < 2147473647) && (lon < 2147473647)) {
						cdmaCell.lat = lat;
						cdmaCell.lon = lon;
					}
					if ((cdmaCell.stationId != -1)
							&& (cdmaCell.networkId != -1)
							&& (cdmaCell.systemId != -1)) {
						cdmaCells.add(0, cdmaCell);
						Vector<CDMACell> tempCells = new Vector<CDMACell>(new HashSet<CDMACell>(
								cdmaCells));
						Collections.sort(tempCells);
						if (tempCells.size() > 10) {
							tempCells.subList(10, tempCells.size()).clear();
						}
						cdmaCells.clear();
						cdmaCells.addAll(tempCells);
					}
				} catch (ClassNotFoundException localClassNotFoundException) {
				}
			}
			show();
		}
		
		public void onServiceStateChanged(ServiceState serviceState) {
			super.onServiceStateChanged(serviceState);
			if (serviceState.getState() != 0){
				if (phoneType == 1) {
					GSMCell gsmCell = new GSMCell(-1, -1, System.currentTimeMillis());
					gsmCells.add(0, gsmCell);
					Vector<GSMCell> tempCells = new Vector<GSMCell>(new HashSet<GSMCell>(gsmCells));
					Collections.sort(gsmCells);
					if (tempCells.size() > 10) {
						tempCells.subList(10, tempCells.size()).clear();
					}
					gsmCells.clear();
					gsmCells.addAll(tempCells);
				} else if (phoneType == 2) {
					CDMACell cdmaCell = new CDMACell();
					cdmaCell.stationId = -1;
					cdmaCell.networkId = -1;
					cdmaCell.systemId = -1;
					cdmaCell.time = System.currentTimeMillis();
					cdmaCell.lat = 0;
					cdmaCell.lon = 0;
					
					cdmaCells.add(0, cdmaCell);
					Vector<CDMACell> tempCells = new Vector<CDMACell>(new HashSet<CDMACell>(cdmaCells));
					Collections.sort(cdmaCells);
					if (tempCells.size() > 10) {
						tempCells.subList(10, tempCells.size()).clear();
					}
					cdmaCells.clear();
					cdmaCells.addAll(tempCells);
				}
				show();	
			}
		}
	};
	
	public void startLBS(){
		if ((this.locationManager.isProviderEnabled("gps"))
				&& (!this.gpsLocationOn)) {
			this.locationManager.requestLocationUpdates("gps", 0L, 0.0F,
					this.gpsLocationListener);
			this.gpsLocationOn = true;
		}
		
		if ((this.locationManager.isProviderEnabled("network"))
				&& (!this.networkLocationOn)) {
			this.locationManager.requestLocationUpdates("network", 0L, 0.0F,
					this.networkLocationListener);
			this.networkLocationOn = true;
		}
	}
	
	private LocationListener networkLocationListener = new LocationListener() {
		//@Override
		public void onLocationChanged(Location loc) {
			lastKnownNetworkLocation.lat = loc.getLatitude();
			lastKnownNetworkLocation.lon = loc.getLongitude();
			lastKnownNetworkLocation.accuracy = loc
					.getAccuracy();
			lastKnownNetworkLocation.time = loc.getTime();
			
		}

		//@Override
		public void onProviderDisabled(String provider) {
			if (provider == "network") {
				locationManager
						.removeUpdates(networkLocationListener);
				networkLocationOn = false;
			}			
		}

		//@Override
		public void onProviderEnabled(String provider) {
			if (provider == "network") {
				locationManager.requestLocationUpdates(
						"network", 0L, 100.0F,networkLocationListener);
				networkLocationOn = true;
			}
			
		}

		//@Override
		public void onStatusChanged(String provider, int status, Bundle extras) {
		}
	};
	
	private LocationListener gpsLocationListener = new LocationListener() {
		public void onLocationChanged(Location location) {
			lastKnownGpsLocation.lat = location.getLatitude();
			lastKnownGpsLocation.lon = location.getLongitude();
			lastKnownGpsLocation.accuracy = location
					.getAccuracy();
			lastKnownGpsLocation.time = location.getTime();
		}

		public void onProviderDisabled(String provider) {
			if (provider == "gps") {
				locationManager
						.removeUpdates(gpsLocationListener);
				gpsLocationOn = false;
			}
		}

		public void onProviderEnabled(String provider) {
			if (provider == "gps") {
				locationManager.requestLocationUpdates("gps",
						0L, 100.0F, gpsLocationListener);
				gpsLocationOn = true;
			}
		}

		public void onStatusChanged(String provider, int status, Bundle extras) {
		}
	};

	private void show(){
		context.show(gsmCells, cdmaCells);
	}
	
	private LBSManager(Context context){
		this.context = (LBSTestActivity)context;
		this.locationManager = ((LocationManager) context.getSystemService("location"));
		this.telephonyManager = ((TelephonyManager) context.getSystemService("phone"));
		
		if (this.telephonyManager!=null)
			this.telephonyManager.listen(this.phoneStateListener, 16);
	}

	private void resetCell() {
		this.gsmCells.clear();
		this.cdmaCells.clear();
	}
	
	public void destroy() {
		resetCell();
		this.telephonyManager.listen(this.phoneStateListener, 0);
		lbsManager = null;
	}
	
	public static LBSManager getInstance(Context context){
		if (lbsManager==null)
			lbsManager=new LBSManager(context);
		return lbsManager;
	}
}
